/**
 * FlowEffectPlugin 类 - 用于创建流动效果的Canvas插件
 * 支持L型、Z型和H型三种形状的管道流动效果
 * 可自定义管道样式、流动效果、颜色渐变等多种参数
 */
class FlowEffectPlugin {
    /**
     * 将 rem 转换为像素
     * @param {number} rem - rem值
     * @returns {number} 像素值
     */
    remToPx(rem) {
        const fontSize = parseFloat(getComputedStyle(document.documentElement).fontSize);
        return rem * fontSize;
    }

    /**
     * 创建流动效果插件实例
     * @param {string} containerId - 容器元素的ID
     * @param {Object} options - 配置选项
     * @param {number} [options.pipeWidth=150] - 管道宽度，单位像素
     * @param {number} [options.pipeHeight=15] - 管道高度，单位像素
     * @param {string} [options.pipeColor='#003366'] - 管道颜色，支持十六进制颜色值
     * @param {string} [options.flowColor='#00ff00'] - 流动效果的颜色
     * @param {number} [options.flowSpeed=2] - 流动速度，值越大速度越快
     * @param {number} [options.flowWidth=8] - 流动效果的宽度，单位像素
     * @param {number} [options.segmentCount=10] - 流动效果的段数
     * @param {number} [options.segmentLength=80] - 每段的长度比例，取值1-100
     * @param {number} [options.segmentGap=20] - 段间距比例，取值0-100
     * @param {string} [options.shape='L'] - 形状类型，可选 'L'、'Z' 或 'H'（横线）
     * @param {number} [options.horizontalLength=50] - 水平方向长度，单位为容器宽度的百分比
     * @param {number} [options.verticalLength=50] - 垂直方向长度，单位为容器高度的百分比
     * @param {number} [options.rotationAngle=0] - 整体旋转角度，0-360度
     * @param {number} [options.brightness=100] - 亮度，取值0-200
     * @param {number} [options.contrast=100] - 对比度，取值0-200
     * @param {number} [options.saturation=100] - 饱和度，取值0-200
     * @param {string} [options.gradientDirection='forward'] - 渐变方向，可选 'forward' 或 'backward'
     * @param {number} [options.energyLength=50] - 能量块长度，单位像素
     * @param {string} [options.flowDirection='forward'] - 流动方向，可选 'forward' 或 'backward'
     * @param {boolean} [options.flipX=false] - 水平翻转
     * @param {boolean} [options.flipY=false] - 垂直翻转
     * @param {boolean} [options.isStopped=false] - 是否停止流动效果
     * @param {boolean} [options.enableGradient=true] - 是否启用渐变效果
     * @param {string} [options.gradientStartColor='#00ff00'] - 渐变起始颜色
     * @param {string} [options.gradientEndColor='#ffffff'] - 渐变结束颜色
     * @throws {Error} 如果找不到指定的容器元素，将抛出错误
     */
    constructor(containerId, options = {}) {
        this.container = document.getElementById(containerId);
        if (!this.container) {
            throw new Error(`Container with id "${containerId}" not found`);
        }

        // 创建canvas元素
        this.canvas = document.createElement('canvas');
        this.ctx = this.canvas.getContext('2d');
        this.container.appendChild(this.canvas);

        // 默认配置
        this.config = {
            pipeWidth: options.pipeWidth || 150,
            pipeHeight: options.pipeHeight || 15,
            pipeColor: options.pipeColor || '#003366',
            segmentCount: options.segmentCount || 10,
            flowSpeed: options.flowSpeed || 2,
            segmentLength: options.segmentLength || 80,
            segmentGap: options.segmentGap || 20,
            flowColor: options.flowColor || '#00ff00',
            flowWidth: options.flowWidth || 8,
            horizontalLength: options.horizontalLength || 50,
            verticalLength: options.verticalLength || 50,
            energyLength: options.energyLength || 50,
            brightness: options.brightness || 100,
            contrast: options.contrast || 100,
            saturation: options.saturation || 100,
            shape: options.shape || 'L',
            gradientDirection: options.gradientDirection || 'forward',
            flowDirection: options.flowDirection || 'forward',
            rotationAngle: options.rotationAngle || 0,
            flipX: options.flipX || false,  // 水平翻转
            flipY: options.flipY || false,   // 垂直翻转
            isStopped: options.isStopped || false,
            enableGradient: options.enableGradient !== undefined ? options.enableGradient : true,
            gradientStartColor: options.gradientStartColor || '#00ff00',
            gradientEndColor: options.gradientEndColor || '#ffffff'
        };

        this.pathPoints = [];
        this.particles = [];
        
        // 初始化
        this.resizeCanvas();
        this.createParticles();
        this.animate();

        // 监听窗口大小变化
        window.addEventListener('resize', () => this.resizeCanvas());
    }

    /**
     * 更新配置参数，会触发路径重新计算和粒子重新创建
     * @param {Object} newOptions - 新的配置参数，格式同构造函数的options参数
     */
    updateConfig(newOptions) {
        Object.assign(this.config, newOptions);
        this.calculatePaths();
        this.createParticles();
    }

    /**
     * 调整Canvas尺寸以适应容器大小
     * 当窗口大小改变时自动调用
     * 会重新计算路径点以保持效果的自适应性
     */
    resizeCanvas() {
        // 获取容器的实际尺寸
        const containerWidth = this.container.clientWidth;
        const containerHeight = this.container.clientHeight || containerWidth;

        // 设置 canvas 尺寸
        this.canvas.width = containerWidth;
        this.canvas.height = containerHeight;

        // 设置 canvas 样式
        this.canvas.style.width = '100%';
        this.canvas.style.height = '100%';
        this.canvas.style.display = 'block';

        this.calculatePaths();
    }

    /**
     * 将角度转换为弧度
     * @param {number} angle - 角度值（0-360）
     * @returns {number} 对应的弧度值（0-2π）
     */
    toRadians(angle) {
        return angle * Math.PI / 180;
    }

    /**
     * 计算管道拐角点的位置，用于创建平滑的转角效果
     * @param {number} startX - 起始点X坐标
     * @param {number} startY - 起始点Y坐标
     * @param {number} endX - 结束点X坐标
     * @param {number} endY - 结束点Y坐标
     * @param {number} angle - 拐角角度，影响转角的圆滑程度
     * @returns {Array<Array<number>>} 拐角点坐标数组，格式为 [[x1, y1], [x2, y2], ...]
     */
    calculateCornerPoints(startX, startY, endX, endY, angle) {
        if (angle === 90) {
            return [[endX, startY]];
        }

        const angleRad = this.toRadians(angle);
        const dy = endY - startY;
        const dx = endX - startX;

        if (dx === 0) {
            const radius = Math.abs(dy) * (1 - Math.tan(angleRad / 2));
            const dirY = Math.sign(dy);
            return [[startX, endY - dirY * radius]];
        } else {
            const radius = Math.abs(dx) * (1 - Math.tan(angleRad / 2));
            const dirX = Math.sign(dx);
            return [[endX - dirX * radius, startY]];
        }
    }

    /**
     * 根据当前配置计算管道的路径点
     * 支持L型、Z型和H型三种形状
     * 路径点会根据容器大小自动调整，实现自适应布局
     * 计算结果存储在 this.pathPoints 中供绘制使用
     */
    calculatePaths() {
        // 获取父容器（center-panel）的尺寸
        const parentContainer = this.container.closest('.center-panel') || document.querySelector('.center-panel');
        if (!parentContainer) {
            console.warn('Cannot find center-panel container');
            return;
        }

        // 获取父容器的实际尺寸（考虑缩放）
        const parentRect = parentContainer.getBoundingClientRect();
        const parentWidth = parentRect.width;
        const parentHeight = parentRect.height;

        // 获取容器的位置信息
        const containerRect = this.container.getBoundingClientRect();
        const containerTop = containerRect.top - parentRect.top;
        
        // 使用父容器尺寸计算实际长度
        const actualHorizontalLength = (this.config.horizontalLength / 100) * parentWidth;
        // 对垂直长度进行特殊处理，考虑容器的相对位置
        const verticalScale = 1 - (containerTop / parentHeight);
        const actualVerticalLength = (this.config.verticalLength / 100) * parentHeight * verticalScale;

        // 基于canvas尺寸计算中心点，但垂直方向考虑容器位置
        const centerX = this.canvas.width / 2;
        const centerY = this.canvas.height * 0.3; // 将中心点稍微上移
        
        const startX = centerX - actualHorizontalLength / 2;
        const startY = centerY;
        
        if (this.config.shape === 'L') {
            const endX = startX + actualHorizontalLength;
            const endY = startY + actualVerticalLength;
            
            this.pathPoints = [
                [startX, startY],  // 起点
                [endX, startY],    // 水平线终点
                [endX, endY]       // 垂直线终点
            ];
        } else if (this.config.shape === 'Z') {
            this.pathPoints = [
                [startX, startY],  // 起始点
                [startX + actualHorizontalLength, startY],  // 第一段水平线终点
                [startX + actualHorizontalLength, startY + actualVerticalLength],  // 垂直线终点
                [startX + actualHorizontalLength * 2, startY + actualVerticalLength]  // 第二段水平线终点
            ];
        } else if (this.config.shape === 'H') {
            this.pathPoints = [
                [startX, centerY],  // 起始点
                [startX + actualHorizontalLength, centerY]  // 终点
            ];
        }

        // 重新创建粒子
        this.createParticles();
    }

    /**
     * 计算路径总长度
     * 通过计算所有路径点之间的距离累加得到
     * @param {Array<Array<number>>} points - 路径点数组，每个点是 [x, y] 格式
     * @returns {number} 路径总长度（像素）
     */
    calculatePathLength(points) {
        let length = 0;
        for (let i = 1; i < points.length; i++) {
            const dx = points[i][0] - points[i-1][0];
            const dy = points[i][1] - points[i-1][1];
            length += Math.sqrt(dx * dx + dy * dy);
        }
        return length;
    }

    /**
     * 获取路径上指定距离处的点位置和角度
     * 用于确定粒子在路径上的精确位置和运动方向
     * @param {Array<Array<number>>} points - 路径点数组
     * @param {number} distance - 从路径起点开始的距离
     * @returns {Object} 位置和角度信息
     * @returns {number} return.x - 点的X坐标
     * @returns {number} return.y - 点的Y坐标
     * @returns {number} return.angle - 该点的切线角度（弧度）
     */
    getPointAtDistance(points, distance) {
        let currentDist = 0;
        
        for (let i = 1; i < points.length; i++) {
            const dx = points[i][0] - points[i-1][0];
            const dy = points[i][1] - points[i-1][1];
            const segmentLength = Math.sqrt(dx * dx + dy * dy);
            
            if (currentDist + segmentLength >= distance) {
                const remainingDist = distance - currentDist;
                const ratio = remainingDist / segmentLength;
                
                return {
                    x: points[i-1][0] + dx * ratio,
                    y: points[i-1][1] + dy * ratio,
                    angle: Math.atan2(dy, dx)
                };
            }
            
            currentDist += segmentLength;
        }
        
        return {
            x: points[points.length-1][0],
            y: points[points.length-1][1],
            angle: 0
        };
    }

    /**
     * 创建流动效果的粒子
     * 根据配置的段数和间距创建均匀分布的粒子
     * 每个粒子包含位置、长度和间隔信息
     * 结果存储在 this.particles 数组中
     */
    createParticles() {
        this.particles = [];
        const pathLength = this.calculatePathLength(this.pathPoints);
        const particleCount = this.config.segmentCount;
        const particleSpacing = pathLength / particleCount;
        
        for (let i = 0; i < particleCount; i++) {
            this.particles.push({
                distance: i * particleSpacing,
                length: (pathLength * this.config.segmentLength) / (100 * particleCount),
                gap: (pathLength * this.config.segmentGap) / (100 * particleCount)
            });
        }
    }

    /**
     * 更新所有粒子的位置
     * 根据flowSpeed移动粒子
     * 当粒子到达路径末端时重置到起点
     * 通过不断调用实现流动动画效果
     */
    updateParticles() {
        const pathLength = this.calculatePathLength(this.pathPoints);
        const direction = this.config.flowDirection === 'forward' ? 1 : -1;
        
        this.particles.forEach(particle => {
            particle.distance += this.config.flowSpeed * direction;
            
            // 处理边界情况
            if (direction > 0 && particle.distance > pathLength) {
                particle.distance = 0;
            } else if (direction < 0 && particle.distance < 0) {
                particle.distance = pathLength;
            }
        });
    }

    /**
     * 调整颜色属性
     * @param {string} color - 输入的十六进制颜色值
     * @returns {string} 调整后的十六进制颜色值
     * 应用亮度、对比度和饱和度设置
     */
    adjustColor(color) {
        const rgb = color.match(/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i);
        if (!rgb) return color;
        
        let [_, r, g, b] = rgb.map(x => parseInt(x, 16));
        
        let [h, s, l] = this.rgbToHsl(r, g, b);
        
        s = Math.min(100, Math.max(0, s * (this.config.saturation / 100)));
        l = Math.min(100, Math.max(0, l * (this.config.brightness / 100)));
        
        if (this.config.contrast !== 100) {
            l = Math.min(100, Math.max(0, 50 + (l - 50) * (this.config.contrast / 100)));
        }
        
        [r, g, b] = this.hslToRgb(h, s, l);
        
        return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
    }

    /**
     * RGB颜色值转换为HSL
     * @param {number} r - 红色值 (0-255)
     * @param {number} g - 绿色值 (0-255)
     * @param {number} b - 蓝色值 (0-255)
     * @returns {Array<number>} HSL值数组 [色相(0-360), 饱和度(0-100), 亮度(0-100)]
     */
    rgbToHsl(r, g, b) {
        r /= 255;
        g /= 255;
        b /= 255;
        
        const max = Math.max(r, g, b);
        const min = Math.min(r, g, b);
        let h, s, l = (max + min) / 2;
        
        if (max === min) {
            h = s = 0;
        } else {
            const d = max - min;
            s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
            
            switch (max) {
                case r: h = (g - b) / d + (g < b ? 6 : 0); break;
                case g: h = (b - r) / d + 2; break;
                case b: h = (r - g) / d + 4; break;
            }
            
            h /= 6;
        }
        
        return [h * 360, s * 100, l * 100];
    }

    /**
     * HSL颜色值转换为RGB
     * @param {number} h - 色相 (0-360)
     * @param {number} s - 饱和度 (0-100)
     * @param {number} l - 亮度 (0-100)
     * @returns {Array<number>} RGB值数组 [r(0-255), g(0-255), b(0-255)]
     */
    hslToRgb(h, s, l) {
        h /= 360;
        s /= 100;
        l /= 100;
        
        let r, g, b;
        
        if (s === 0) {
            r = g = b = l;
        } else {
            const hue2rgb = (p, q, t) => {
                if (t < 0) t += 1;
                if (t > 1) t -= 1;
                if (t < 1/6) return p + (q - p) * 6 * t;
                if (t < 1/2) return q;
                if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
                return p;
            };
            
            const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
            const p = 2 * l - q;
            
            r = hue2rgb(p, q, h + 1/3);
            g = hue2rgb(p, q, h);
            b = hue2rgb(p, q, h - 1/3);
        }
        
        return [
            Math.round(r * 255),
            Math.round(g * 255),
            Math.round(b * 255)
        ];
    }

    /**
     * 绘制管道
     * @param {CanvasRenderingContext2D} ctx - Canvas上下文
     * @param {Array<Array<number>>} points - 路径点数组
     * 使用 pipeColor 和 pipeHeight 设置绘制管道
     */
    drawPipe(ctx, points) {
        ctx.save();
        ctx.strokeStyle = this.adjustColor(this.config.pipeColor);
        ctx.lineWidth = this.config.pipeHeight;
        ctx.lineCap = 'round';
        ctx.lineJoin = 'round';
        
        ctx.beginPath();
        ctx.moveTo(points[0][0], points[0][1]);
        
        for (let i = 1; i < points.length; i++) {
            ctx.lineTo(points[i][0], points[i][1]);
        }
        
        ctx.stroke();
        ctx.restore();
    }

    /**
     * 绘制流动粒子效果
     * @param {CanvasRenderingContext2D} ctx - Canvas上下文
     * @param {Array<Array<number>>} points - 路径点数组
     * 根据配置绘制流动效果，包括渐变和粒子动画
     */
    drawParticles(ctx, points) {
        ctx.save();
        
        this.particles.forEach(particle => {
            const start = this.getPointAtDistance(points, particle.distance);
            const end = this.getPointAtDistance(points, particle.distance + particle.length);
            
            let gradient;
            if (this.config.enableGradient) {
                gradient = ctx.createLinearGradient(start.x, start.y, end.x, end.y);
                const startColor = this.adjustColor(this.config.gradientStartColor);
                const endColor = this.adjustColor(this.config.gradientEndColor);
                if (this.config.gradientDirection === 'forward') {
                    gradient.addColorStop(0, startColor);
                    gradient.addColorStop(1, endColor);
                } else {
                    gradient.addColorStop(0, endColor);
                    gradient.addColorStop(1, startColor);
                }
            } else {
                gradient = this.adjustColor(this.config.flowColor);
            }
            
            ctx.strokeStyle = gradient;
            ctx.lineWidth = this.config.flowWidth;
            ctx.lineCap = 'round';
            
            ctx.beginPath();
            ctx.moveTo(start.x, start.y);
            ctx.lineTo(end.x, end.y);
            ctx.stroke();
        });
        
        ctx.restore();
    }

    /**
     * 动画循环函数
     * 清除画布、更新粒子位置并重新绘制
     * 使用 requestAnimationFrame 实现平滑动画
     */
    animate() {
        if (this.config.isStopped) {
            this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
            this.ctx.save();
            this.ctx.translate(this.canvas.width/2, this.canvas.height/2);
            this.ctx.rotate(this.toRadians(this.config.rotationAngle));
            const scaleX = this.config.flipX ? -1 : 1;
            const scaleY = this.config.flipY ? -1 : 1;
            this.ctx.scale(scaleX, scaleY);
            this.ctx.translate(-this.canvas.width/2, -this.canvas.height/2);
            this.drawPipe(this.ctx, this.pathPoints);
            this.ctx.restore();
            return;
        }
        
        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
        
        // 应用变换
        this.ctx.save();
        
        // 移动到画布中心
        this.ctx.translate(this.canvas.width/2, this.canvas.height/2);
        
        // 应用旋转
        this.ctx.rotate(this.toRadians(this.config.rotationAngle));
        
        // 应用翻转
        const scaleX = this.config.flipX ? -1 : 1;
        const scaleY = this.config.flipY ? -1 : 1;
        this.ctx.scale(scaleX, scaleY);
        
        // 移回原位置
        this.ctx.translate(-this.canvas.width/2, -this.canvas.height/2);
        
        this.drawPipe(this.ctx, this.pathPoints);
        this.drawParticles(this.ctx, this.pathPoints);
        
        this.ctx.restore();
        
        this.updateParticles();
        requestAnimationFrame(() => this.animate());
    }

    /**
     * 切换流动效果的状态
     */
    toggleFlow() {
        this.config.isStopped = !this.config.isStopped;
    }

    /**
     * 销毁插件实例
     * 移除事件监听器和Canvas元素
     * 在不再需要插件时调用此方法释放资源
     */
    destroy() {
        window.removeEventListener('resize', () => this.resizeCanvas());
        this.container.removeChild(this.canvas);
    }
}

export default FlowEffectPlugin;
